/*
 * file:   neiku/render.h
 * desc:   任意对象到字符串的渲染工具
 * author: YIF
 * date:   2023/07/15 11:45:00
 *
 * version: v1  -- map encode
 *              基于C++的重载、宏技术，简单实现C++对象自动转成字符串map对象
 *              简单支持int32/64,uint32/64,std::string,std::map<std::string,std::string>
 *          v2  -- render
 *              基于map decode能力实现任意对象到字符串的渲染
 *          v3  -- render
 *              支持常量类型，并兼容非常量
 * usage:
 *       #include "neiku/render.h"
 *
 * compile: $(neiku_config --include --libs render)
 *
 * vim:ts=4;sw=4;expandtab
 */

#ifndef __NK_RENDER_H__
#define __NK_RENDER_H__ 1

#include <inttypes.h>
#include <string>
#include <map>
#include "neiku/serialize.h"

#define map_encode(obj) ((neiku::CMapEncoder()<<obj).map())

namespace neiku
{

class CMapEncoder
{
    public:
        std::map<std::string, std::string> m_map;
        const char*  m_key;

        CMapEncoder()
        {}

        template <class T>
        CMapEncoder& operator << (T& o)
        {
            o.serialize(*this);
            return *this;
        }

        template <class T>
        CMapEncoder& operator << (const T& o)
        {
            *this << const_cast<T>(o);
            return *this;
        }

        CMapEncoder& operator << (const std::map<std::string, std::string>& o)
        {
            m_map = o;
            return *this;
        }

        std::map<std::string, std::string> map()
        {
            return m_map;
        }

    public:
        CMapEncoder& operator & (Key& key)
        {
            m_key = key.c_str();
            return *this;
        }

        CMapEncoder& operator & (std::string& s)
        {
            m_map[m_key] = s;
            return *this;
        }

        #define GEN_NUMBER_OPERATOR(type, fmt) \
                CMapEncoder& operator & (type& n) \
        { \
            char tmp[11]={0}; \
            snprintf(tmp, sizeof(tmp), fmt, n); \
            m_map[m_key] = tmp; \
            return *this; \
        }
        GEN_NUMBER_OPERATOR(int32_t, "%d")
        GEN_NUMBER_OPERATOR(int64_t, "%ld")
        GEN_NUMBER_OPERATOR(uint32_t, "%u")
        GEN_NUMBER_OPERATOR(uint64_t, "%lu")
};

// render: 任意对象转字符串map, pattern示例：hi {name}，其中name取自 object 的 name 成员。
template<typename T>
std::string render(T& object, const std::string& pattern)
{
    std::map<std::string, std::string> params = map_encode(object);
    std::string result(pattern);
    for (std::map<std::string, std::string>::iterator it = params.begin();
        it != params.end(); it++) {
        char tmp[32]={0};
        snprintf(tmp, sizeof(tmp),"{%s}", it->first.c_str());

        std::string hold(tmp);
        for (std::string::size_type pos(0); pos != std::string::npos; pos += it->second.length()) {
            pos = result.find(hold, pos);
            if (pos == std::string::npos) {
                break;
            }
            result.replace(pos, hold.length(), it->second);
        }
    }
    return result;
}

}

#endif